package com.putprize.percy

import org.apache.log4j.Logger

import scala.collection.mutable.ArrayBuffer

import scala.collection.mutable.{HashMap => HMap}

import scala.util.Random

import scala.io.Source
import java.io.PrintWriter

object PyotrStream {
  
  val _log = Logger.getLogger(this.getClass.getName)
  
  def saveTopic(R:Map[String,Array[Double]], location:String) = {
    val out = new PrintWriter(location)
    R.foreach(nt => {
      val n = nt._1
      val t = nt._2
      val zs = (0 until t.size).par.
      				map(z => {(z,t(z))})
      			.filter(zt => (zt._2 > 1.0))
      val line =
        if (zs.size > 0)
          zs.map(zt => {zt._1.toString+":"+zt._2.toString}).reduce(_+" "+_)
        else
          ""
      out.write(n+"\t"+line+"\n")
    })
    out.close
  }
  
  def runOne(
		  locationSize:String,
		  locationData:String,
		  locationCountT:String,
		  locationCountV:String,
		  maxIter:Int,
		  minConv:Double
      ) = {
    
    _log.info("Init Data ...")
    val x = Data.initSize(locationSize)
    
    val (ms,ns) = Data.initData(locationData)
    _log.info("Init Data Done")
    
    val x1 = x._1
    val x2 = x._2
    
    val m = PyotrEstimater.run_em(ms,ns, x._1,x._2,x._3,maxIter,minConv)
    
    _log.info("Done ")
    
    PyotrModel.saveCountT(m.asInstanceOf[Model2].countT, locationCountT)
    PyotrModel.saveCountV(m.asInstanceOf[Model2].countT, m.asInstanceOf[Model2].countV, locationCountV)
    
  }
  
 
  def runNew(
		  	locationSize:String,
		  	locationData:String,
		  	locationCT:String,
		  	locationCV:String,
		  	locationInit:String,
		  	init:Int, // Init Mode
		  	ROOT:String,
		  	//K:Int, // Topic Num
		  	I:Int, // Max Iter Num
		  	M:Int, // Mode: Incremental Or All
		  	B:Int, // Batch Size
		  	N:Int, // Start Num
		  	T:Int, // Export Document Topic?
		  	we:Double // Weak Supervision
      ) = {
    
    _log.info("SaveTheta "+T)
    
    _log.info("Begin ...")
    val s = Data.initSize(locationSize)
    val Nv = s._1
    val Mv = s._2
    val K = s._3
    
    var R = Map[String,Array[Double]]()
    
    _log.info("Get Data ")
    val data = Data.initData(locationData)
    val Xs = data._1
    val Zs = data._2
    _log.info("Get Data Done")
    
    _log.info("Init "+init)
    
    val model =
      if (init == 0){ // 全量
        PyotrModel.initModel(K,Mv,Xs)
      }
      else { // 增量
        _log.info("Init V")
        val V = new HMap[Int,Double]
        Xs.foreach(x => {
          val n = x._2.n
          (0 until n).foreach(j => {
            val v = x._2.vs(j)
            val c = x._2.cs(j)
            val vc = V.getOrElse(v,0.0)
            V(v) = vc+c
          })
        })
        _log.info("Init V Done")
        PyotrModel.initModel(K, Mv, V.toMap, locationInit)
      }
   
    val C =
      if (init == 0) 0
      else Nv
      
    _log.info("Init Model Done")
    
    val ns = Xs.keySet.toArray
    val cc = B
    val CC = ns.size/cc+1
    _log.info(Xs.size)
    
    val mode = M
    
    // 默认空文档
    val cDc = new Document(Array[Int](),Array[Float](),0)
    
    val U = new PyotrUpdater(model,Nv,Mv,mode,C,N,we)
    
    (0 until I).foreach{ i =>
      _log.info("i "+i)
      val vvs = Random.shuffle((1 to ns.size)).toArray
      _log.info(vvs.slice(0,10).map(_.toString).reduce(_+" "+_))
      (0 until CC).foreach { j =>
        val ii = i*CC+j
        var i1 = (ii%CC)*cc
        var i2 = i1+cc
        if (i1 > ns.size)
          i1 = ns.size
        if (i2 > ns.size)
          i2 = ns.size
        _log.info(i1+" "+i2)
        val nns = vvs.slice(i1,i2).map(v => ns(v-1)).toArray
        _log.info(nns.size)
        if (nns.size > 0){
          val xs = nns.map(n => (n,Xs.getOrElse(n, cDc))).toMap
          val zs = nns.map(n => (n,Zs.getOrElse(n,List[Int]()))).toMap
          val rs = U.run_em(xs, zs)
          if (T > 0){
            R = R++rs
          }
        }
        _log.info("ii "+i+" "+ii+" "+CC+" "+ii%CC)
      }
      
      if (i > 0 && i % 2 == 0){
        PyotrModel.saveCountT(model.countT,ROOT+"/"+locationCT+"_Done_"+i)
        PyotrModel.saveCountV(model.countT,model.countV,ROOT+"/"+locationCV+"_Done_"+i)
        if (T > 0){
          saveTopic(R,ROOT+"/InferedTopic_"+i+".txt")
        }
      }
    }
    
    PyotrModel.saveCountT(model.countT, ROOT+"/"+locationCT)
    PyotrModel.saveCountV(model.countT,model.countV,ROOT+"/"+locationCV)
    if (T > 0){
      saveTopic(R,ROOT+"/InferredTopic_Done.txt")
    }

  }

}
